define(['lib/ammo', 'lib/Three'],
       function(Ammo, THREE) {

var ammothreeutil = {};

/**
 * Creates an aligned static Ammo shape and THREE mesh. Origin is a geometry3d
 * or geometry2d vector where z is implicitly 0.
 */
ammothreeutil.createStaticBox = function(
  xLength, yLength, zLength, origin, axis, revolutions) {
  var shape = new Ammo.btBoxShape(
    new Ammo.btVector3(xLength / 2, yLength / 2, zLength / 2));
  var transform = new Ammo.btTransform();
  transform.setIdentity();
  transform.setOrigin(makeAmmoVector(origin));
  transform.setRotation(new Ammo.btQuaternion(
    makeAmmoVector(axis), revolutions * 2 * Math.PI));

  var inertia = new Ammo.btVector3(0, 0, 0);
  var motionState = new Ammo.btDefaultMotionState(transform);
  var constructionInfo = new Ammo.btRigidBodyConstructionInfo(
    0, motionState, shape, inertia);
  var body = new Ammo.btRigidBody(constructionInfo);

  var mesh = new THREE.Mesh(
    new THREE.CubeGeometry(xLength, yLength, zLength),
    new THREE.MeshLambertMaterial( { color: 0xFFFF00 } ));
  copyVector(origin, mesh.position);
  mesh.useQuaternion = true;
  mesh.quaternion = new THREE.Quaternion().setFromAxisAngle(
    makeThreeVector(axis), revolutions * 2 * Math.PI);

  return {
    body: body,
    mesh: mesh };
};

/**
 * Creates an Ammo vector. Source can be any other kind of vector, including
 * 2D.
 */
function makeAmmoVector(source) {
  var vector = new Ammo.btVector3();
  setVectorFromArray(vectorToArray(source), vector);
  return vector;
}

/**
 * Creates a Three.js vector. Source can be any other kind of vector, including
 * 2D.
 */
function makeThreeVector(source) {
  var vector = new THREE.Vector3();
  setVectorFromArray(vectorToArray(source), vector);
  return vector;
}

/**
 * Copies the source vector to the target vector. Works with geometry2d, Ammo
 * and THREE vectors. geometry2d vectors are assumed to have z values of 0.
 */
function copyVector(source, destination) {
  setVectorFromArray(vectorToArray(source), destination);
}

/**
 * Returns an array where index 0 is the x value of the vector, etc. Works with
 * geometry2d, Ammo and THREE vectors. geometry2d vectors are assumed to have z
 * values of 0.
 */
function vectorToArray(vector) {
  if (isAmmoVector(vector)) {
    return [vector.getX(), vector.getY(), vector.getZ()];
  } else if (isGeometry2dVector(vector)) {
    return [vector.x, vector.y, 0];
  } else {  // Any vector w/ x, y, z properties.
    return [vector.x, vector.y, vector.z];
  }
}

/**
 * Sets an Ammo or THREE vector from the source array. The source array must
 * have three elements.
 */
function setVectorFromArray(sourceArray, destinationVector) {
  if (isAmmoVector(destinationVector)) {
    destinationVector.setX(sourceArray[0]);
    destinationVector.setY(sourceArray[1]);
    destinationVector.setZ(sourceArray[2]);
  } else {
    destinationVector.x = sourceArray[0];
    destinationVector.y = sourceArray[1];
    destinationVector.z = sourceArray[2];
  }
}

function isAmmoVector(vector) {
  return typeof vector.getX == 'function';
}

function isGeometry2dVector(vector) {
  return (vector.x != undefined) &&
    (vector.y != undefined) &&
    (vector.z == undefined);
}

return ammothreeutil;

});
